diff --git a/.clang-format b/.clang-format
index 7fc30f614..7dbeea784 100644
--- a/.clang-format
+++ b/.clang-format
@@ -77,6 +77,12 @@ IncludeCategories:
   - Regex:           '<Q([A-Za-z0-9\-_])+>'
     CaseSensitive:   true
     Priority:        9
+  # Python.h hence pybind11 headers must be included first
+  # https://docs.python.org/3/c-api/intro.html#include-files
+  - Regex:           '<pybind11/.*>'
+    Priority:        -9
+  - Regex:           '"py_.*"'
+    Priority:        -8
   # Headers in <> with an extension. (+system libraries)
   - Regex:           '<([A-Za-z0-9\-_])+\.h>'
     Priority:        2
diff --git a/Documentation/coding-style.rst b/Documentation/coding-style.rst
index 3352b75c7..e0864b78d 100644
--- a/Documentation/coding-style.rst
+++ b/Documentation/coding-style.rst
@@ -95,6 +95,12 @@ System and library headers shall be included with angle brackets. Project
 headers shall be included with angle brackets for the libcamera public API
 headers, and with double quotes for internal libcamera headers.

+.. note::
+   As an exception pybind11 headers and local ``py_*`` headers must be included first
+   in the Python bindings due to the requirements outlined in the `Python documentation`_.
+
+.. _Python documentation: https://docs.python.org/3/c-api/intro.html#include-files
+

 C++ Specific Rules
 ------------------
diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h
index af69b915e..7da65172e 100644
--- a/src/py/libcamera/py_camera_manager.h
+++ b/src/py/libcamera/py_camera_manager.h
@@ -5,12 +5,12 @@

 #pragma once

+#include <pybind11/pybind11.h>
+
 #include <libcamera/base/mutex.h>

 #include <libcamera/libcamera.h>

-#include <pybind11/pybind11.h>
-
 using namespace libcamera;

 class PyCameraManager
diff --git a/src/py/libcamera/py_color_space.cpp b/src/py/libcamera/py_color_space.cpp
index fd5a5dabe..2f4d2d891 100644
--- a/src/py/libcamera/py_color_space.cpp
+++ b/src/py/libcamera/py_color_space.cpp
@@ -5,15 +5,15 @@
  * Python bindings - Color Space classes
  */

-#include <libcamera/color_space.h>
-#include <libcamera/libcamera.h>
-
 #include <pybind11/operators.h>
 #include <pybind11/pybind11.h>
 #include <pybind11/stl.h>

 #include "py_main.h"

+#include <libcamera/color_space.h>
+#include <libcamera/libcamera.h>
+
 namespace py = pybind11;

 using namespace libcamera;
diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
index 22a132d19..c42a477bb 100644
--- a/src/py/libcamera/py_controls_generated.cpp.in
+++ b/src/py/libcamera/py_controls_generated.cpp.in
@@ -7,12 +7,12 @@
  * This file is auto-generated. Do not edit.
  */

-#include <libcamera/{{header}}>
-
 #include <pybind11/pybind11.h>

 #include "py_main.h"

+#include <libcamera/{{header}}>
+
 namespace py = pybind11;

 class Py{{mode|capitalize}}
diff --git a/src/py/libcamera/py_enums.cpp b/src/py/libcamera/py_enums.cpp
index 9e75ec1a9..715b63880 100644
--- a/src/py/libcamera/py_enums.cpp
+++ b/src/py/libcamera/py_enums.cpp
@@ -5,12 +5,12 @@
  * Python bindings - Enumerations
  */

-#include <libcamera/libcamera.h>
-
 #include <pybind11/pybind11.h>

 #include "py_main.h"

+#include <libcamera/libcamera.h>
+
 namespace py = pybind11;

 using namespace libcamera;
diff --git a/src/py/libcamera/py_formats_generated.cpp.in b/src/py/libcamera/py_formats_generated.cpp.in
index c5fb90639..bd0ccdc3e 100644
--- a/src/py/libcamera/py_formats_generated.cpp.in
+++ b/src/py/libcamera/py_formats_generated.cpp.in
@@ -7,10 +7,10 @@
  * This file is auto-generated. Do not edit.
  */

-#include <libcamera/formats.h>
-
 #include <pybind11/pybind11.h>

+#include <libcamera/formats.h>
+
 #include "py_main.h"

 namespace py = pybind11;
diff --git a/src/py/libcamera/py_geometry.cpp b/src/py/libcamera/py_geometry.cpp
index c7e303609..d96015f03 100644
--- a/src/py/libcamera/py_geometry.cpp
+++ b/src/py/libcamera/py_geometry.cpp
@@ -5,17 +5,17 @@
  * Python bindings - Geometry classes
  */

-#include <array>
-
-#include <libcamera/geometry.h>
-#include <libcamera/libcamera.h>
-
 #include <pybind11/operators.h>
 #include <pybind11/pybind11.h>
 #include <pybind11/stl.h>

 #include "py_main.h"

+#include <array>
+
+#include <libcamera/geometry.h>
+#include <libcamera/libcamera.h>
+
 namespace py = pybind11;

 using namespace libcamera;
diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp
index 8c55ef845..b9142225c 100644
--- a/src/py/libcamera/py_helpers.cpp
+++ b/src/py/libcamera/py_helpers.cpp
@@ -3,14 +3,14 @@
  * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
  */

-#include "py_helpers.h"
-
-#include <libcamera/libcamera.h>
-
 #include <pybind11/functional.h>
 #include <pybind11/stl.h>
 #include <pybind11/stl_bind.h>

+#include "py_helpers.h"
+
+#include <libcamera/libcamera.h>
+
 namespace py = pybind11;

 using namespace libcamera;
diff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h
index 983969dff..989fae77b 100644
--- a/src/py/libcamera/py_helpers.h
+++ b/src/py/libcamera/py_helpers.h
@@ -5,9 +5,9 @@

 #pragma once

-#include <libcamera/libcamera.h>
-
 #include <pybind11/pybind11.h>

+#include <libcamera/libcamera.h>
+
 pybind11::object controlValueToPy(const libcamera::ControlValue &cv);
 libcamera::ControlValue pyToControlValue(const pybind11::object &ob, libcamera::ControlType type);
diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
index a983ea75c..d0ef6915b 100644
--- a/src/py/libcamera/py_main.cpp
+++ b/src/py/libcamera/py_main.cpp
@@ -5,6 +5,13 @@
  * Python bindings
  */

+#include <pybind11/functional.h>
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include <pybind11/stl_bind.h>
+
+#include "py_camera_manager.h"
+#include "py_helpers.h"
 #include "py_main.h"

 #include <limits>
@@ -17,14 +24,6 @@

 #include <libcamera/libcamera.h>

-#include <pybind11/functional.h>
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-#include <pybind11/stl_bind.h>
-
-#include "py_camera_manager.h"
-#include "py_helpers.h"
-
 namespace py = pybind11;

 using namespace libcamera;
diff --git a/src/py/libcamera/py_main.h b/src/py/libcamera/py_main.h
index 4d594326e..dd31c6d9a 100644
--- a/src/py/libcamera/py_main.h
+++ b/src/py/libcamera/py_main.h
@@ -5,10 +5,10 @@

 #pragma once

-#include <libcamera/base/log.h>
-
 #include <pybind11/pybind11.h>

+#include <libcamera/base/log.h>
+
 namespace libcamera {

 LOG_DECLARE_CATEGORY(Python)
diff --git a/src/py/libcamera/py_transform.cpp b/src/py/libcamera/py_transform.cpp
index 768260ffc..8719b5ff5 100644
--- a/src/py/libcamera/py_transform.cpp
+++ b/src/py/libcamera/py_transform.cpp
@@ -5,15 +5,15 @@
  * Python bindings - Transform class
  */

-#include <libcamera/transform.h>
-#include <libcamera/libcamera.h>
-
 #include <pybind11/operators.h>
 #include <pybind11/pybind11.h>
 #include <pybind11/stl.h>

 #include "py_main.h"

+#include <libcamera/transform.h>
+#include <libcamera/libcamera.h>
+
 namespace py = pybind11;

 using namespace libcamera;
