diff --git a/CMakeLists.txt b/CMakeLists.txt
index ec07537df35c46518a3e9899c3230e4709d6e1d5..bcc8f9897f45aeb0ef2b2ebbb720f82ec45cde4f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -220,6 +220,7 @@ set(${PROJECT_NAME}_HEADERS
     ${${PROJECT_NAME}_DECOMPOSITIONS_HEADERS}
     include/eigenpy/alignment.hpp
     include/eigenpy/computation-info.hpp
+    include/eigenpy/deprecation-policy.hpp
     include/eigenpy/eigenpy.hpp
     include/eigenpy/exception.hpp
     include/eigenpy/scalar-conversion.hpp
diff --git a/include/eigenpy/deprecation-policy.hpp b/include/eigenpy/deprecation-policy.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c1635ea1703557841a115d70599ecf1b6f725e25
--- /dev/null
+++ b/include/eigenpy/deprecation-policy.hpp
@@ -0,0 +1,62 @@
+//
+// Copyright (C) 2024 LAAS-CNRS, INRIA
+//
+#ifndef __eigenpy_deprecation_hpp__
+#define __eigenpy_deprecation_hpp__
+
+#include "eigenpy/fwd.hpp"
+
+namespace eigenpy {
+
+enum class DeprecationType { DEPRECATION, FUTURE };
+
+namespace detail {
+
+constexpr PyObject *deprecationTypeToPyObj(DeprecationType dep) {
+  switch (dep) {
+    case DeprecationType::DEPRECATION:
+      return PyExc_DeprecationWarning;
+    case DeprecationType::FUTURE:
+      return PyExc_FutureWarning;
+  }
+}
+
+}  // namespace detail
+
+constexpr char defaultDeprecationMessage[] =
+    "This function or attribute has been marked as deprecated, and will be "
+    "removed in the "
+    "future.";
+
+/// @brief A Boost.Python call policy which triggers a Python warning on
+/// precall.
+template <DeprecationType deprecation_type = DeprecationType::DEPRECATION,
+          class BasePolicy = bp::default_call_policies>
+struct deprecation_warning_policy : BasePolicy {
+  using result_converter = typename BasePolicy::result_converter;
+  using argument_package = typename BasePolicy::argument_package;
+
+  deprecation_warning_policy(
+      const std::string &warning_msg = defaultDeprecationMessage)
+      : BasePolicy(), m_what(warning_msg) {}
+
+  const std::string what() const { return m_what; }
+
+  const BasePolicy *derived() const {
+    return static_cast<const BasePolicy *>(this);
+  }
+
+  template <class ArgPackage>
+  bool precall(const ArgPackage &args) const {
+    PyErr_WarnEx(detail::deprecationTypeToPyObj(deprecation_type),
+                 m_what.c_str(), 1);
+    return derived()->precall(args);
+  }
+
+ private:
+  const std::string m_what;
+};
+
+}  // namespace eigenpy
+
+#endif  // ifndef __eigenpy_deprecation_hpp__
diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt
index 09b35a02727f7008b6ca737847e0a537c5d9c4c9..d0c216fb56eb7bd230d90e20fd73bba63bf11a5c 100644
--- a/unittest/CMakeLists.txt
+++ b/unittest/CMakeLists.txt
@@ -37,6 +37,7 @@ endif()
 add_lib_unit_test(tensor)
 add_lib_unit_test(geometry)
 add_lib_unit_test(complex)
+add_lib_unit_test(deprecation_policy)
 add_lib_unit_test(return_by_ref)
 add_lib_unit_test(include)
 if(NOT ${EIGEN3_VERSION} VERSION_LESS "3.2.0")
@@ -104,6 +105,8 @@ add_python_lib_unit_test("py-matrix" "unittest/python/test_matrix.py")
 add_python_lib_unit_test("py-tensor" "unittest/python/test_tensor.py")
 add_python_lib_unit_test("py-geometry" "unittest/python/test_geometry.py")
 add_python_lib_unit_test("py-complex" "unittest/python/test_complex.py")
+add_python_lib_unit_test("py-deprecation-policy"
+                         "unittest/python/test_deprecation_policy.py")
 add_python_lib_unit_test("py-return-by-ref"
                          "unittest/python/test_return_by_ref.py")
 add_python_lib_unit_test("py-eigen-ref" "unittest/python/test_eigen_ref.py")
diff --git a/unittest/deprecation_policy.cpp b/unittest/deprecation_policy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d06d4954fff9804228b42495f64bc4579b64ed85
--- /dev/null
+++ b/unittest/deprecation_policy.cpp
@@ -0,0 +1,24 @@
+#include "eigenpy/eigenpy.hpp"
+#include "eigenpy/deprecation-policy.hpp"
+
+#include <iostream>
+
+namespace bp = boost::python;
+using eigenpy::DeprecationType;
+
+void some_deprecated_function() {
+  std::cout << "Calling this should produce a warning" << std::endl;
+}
+
+void some_future_deprecated_function() {
+  std::cout
+      << "Calling this should produce a warning about a future deprecation"
+      << std::endl;
+}
+
+BOOST_PYTHON_MODULE(deprecation_policy) {
+  bp::def("some_deprecated_function", some_deprecated_function,
+          eigenpy::deprecation_warning_policy<DeprecationType::DEPRECATION>());
+  bp::def("some_future_deprecated_function", some_future_deprecated_function,
+          eigenpy::deprecation_warning_policy<DeprecationType::FUTURE>());
+}
diff --git a/unittest/python/test_deprecation_policy.py b/unittest/python/test_deprecation_policy.py
new file mode 100644
index 0000000000000000000000000000000000000000..b47550c7536f828e40d764e4f4f7a383fff2d701
--- /dev/null
+++ b/unittest/python/test_deprecation_policy.py
@@ -0,0 +1,4 @@
+from deprecation_policy import some_deprecated_function, some_future_deprecated_function
+
+some_deprecated_function()
+some_future_deprecated_function()