--- a/python/dolfin/__init__.py
+++ b/python/dolfin/__init__.py
@@ -30,6 +30,32 @@
 # sys.setdlopenflags(stored_dlopen_flags)
 # del sys
 
+import pusimp
+
+def pip_uninstall_call(executable: str, dependency_pypi_name: str, dependency_actual_path: str) -> str:
+    """Report to the user how to uninstall a dependency with pip."""
+    output = f"{executable} -m pip uninstall --break-system-packages {dependency_pypi_name}"
+    if dependency_actual_path.startswith("/usr"):
+        return f"sudo {output}"
+    else:
+        return output
+
+
+pusimp.prevent_user_site_imports(
+    "dolfin", "apt", "https://fenicsproject.discourse.group/",
+    "/usr/lib/python3/dist-packages",
+    ["dijitso", "ffc", "FIAT", "ufl_legacy", "ufl"],
+    ["fenics-dijitso", "fenics-ffc", "fenics-fiat", "fenics-ufl-legacy", "fenics-ufl"],
+    [False, False, False, False, True],
+    ["", "", "", "", (
+        "Be aware that legacy dolfin codes must now import ufl_legacy instead of ufl, "
+        "see https://fenicsproject.discourse.group/t/announcement-ufl-legacy-and-legacy-dolfin/11583 ."
+    )],
+    pip_uninstall_call
+)
+
+del pip_uninstall_call, pusimp
+
 # Import cpp modules
 from .cpp import __version__
 
--- /dev/null
+++ b/python/test/debian-only/test_pusimp.py
@@ -0,0 +1,101 @@
+# Copyright (C) 2024 by the pusimp authors
+#
+# This file is part of pusimp for FEniCS.
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+"""Test DOLFIN patches."""
+
+import typing
+
+import pytest
+import requests
+
+from pusimp.utils import (
+    assert_package_import_errors_with_local_packages,
+    assert_package_import_errors_with_broken_non_optional_packages,
+    assert_package_import_success_with_allowed_local_packages,
+    assert_package_import_success_with_broken_optional_packages,
+    assert_package_import_success_without_local_packages
+)
+
+try:
+    response = requests.get("https://www.debian.org", timeout=5)
+except requests.ConnectionError:
+    has_internet = False
+else:
+    has_internet = True
+
+UFL_LEGACY_WARNING = "legacy dolfin codes must now import ufl_legacy instead of ufl"
+
+
+def pip_install_call(executable: str, dependency_pypi_name: str) -> str:
+    """Command to be run to install a dependency with pip."""
+    return (
+        f"{executable} -m pip install --ignore-installed --break-system-packages {dependency_pypi_name}"
+        # debian does not ship numpy 2.0 yet, and a pip install-ed numpy 2.0 would break binary compatibility
+        + " 'numpy<2.0'"
+    )
+
+
+def pip_uninstall_call(executable: str, dependency_pypi_name: str, dependency_actual_path: str) -> str:
+    """Command to be run to uninstall a dependency with pip."""
+    return f"{executable} -m pip uninstall --break-system-packages {dependency_pypi_name}"
+
+
+def test_dolfin_import_success_without_local_packages() -> None:
+    """Test that dolfin imports correctly without any extra local packages."""
+    assert_package_import_success_without_local_packages(
+        "dolfin", "/usr/lib/petsc/lib/python3/dist-packages/dolfin/__init__.py"
+    )
+
+
+@pytest.mark.skipif(not has_internet, reason="Requires downloading from pypi.org")
+@pytest.mark.parametrize("dependencies_import_name,dependencies_pypi_name,dependencies_extra_error_message", [
+    (["ufl_legacy"], ["fenics-ufl-legacy"], []),
+    (["ufl"], ["fenics-ufl"], [UFL_LEGACY_WARNING]),
+    (["FIAT", "ufl_legacy"], ["fenics-fiat", "fenics-ufl-legacy"], []),
+    (["ufl", "ufl_legacy"], ["fenics-ufl", "fenics-ufl-legacy"], [UFL_LEGACY_WARNING])
+])
+def test_dolfin_import_errors_with_local_packages(
+    dependencies_import_name: typing.List[str], dependencies_pypi_name: typing.List[str],
+    dependencies_extra_error_message: typing.List[str]
+) -> None:
+    """Test that dolfin fails to import with extra local packages."""
+    assert_package_import_errors_with_local_packages(
+        "dolfin", dependencies_import_name, dependencies_pypi_name, dependencies_extra_error_message,
+        pip_install_call, pip_uninstall_call
+    )
+
+
+@pytest.mark.skipif(not has_internet, reason="Requires downloading from pypi.org")
+@pytest.mark.parametrize("dependencies_import_name,dependencies_pypi_name", [
+    (["ufl_legacy"], ["fenics-ufl-legacy"]),
+    (["ufl"], ["fenics-ufl"])
+])
+def test_dolfin_import_success_with_allowed_local_packages(
+    dependencies_import_name: typing.List[str], dependencies_pypi_name: typing.List[str]
+) -> None:
+    """Test that dolfin imports correctly even with extra local packages when asked to allow user-site imports."""
+    assert_package_import_success_with_allowed_local_packages(
+        "dolfin", "/usr/lib/petsc/lib/python3/dist-packages/dolfin/__init__.py",
+        dependencies_import_name, dependencies_pypi_name, pip_install_call
+    )
+
+
+@pytest.mark.parametrize("dependencies_import_name", [
+    ["ufl_legacy"],  # also breaks ffc/compiler.py (line 121)
+    ["ffc"]
+])
+def test_dolfin_import_errors_with_broken_non_optional_packages(dependencies_import_name: typing.List[str]) -> None:
+    """Test that dolfin fails to import when non-optional packages are broken."""
+    assert_package_import_errors_with_broken_non_optional_packages("dolfin", dependencies_import_name, [False])
+
+
+@pytest.mark.parametrize("dependencies_import_name", [
+    ["ufl"]
+])
+def test_dolfin_import_success_with_broken_optional_packages(dependencies_import_name: typing.List[str]) -> None:
+    """Test that dolfin fails to import imports correctly when optional packages are broken."""
+    assert_package_import_success_with_broken_optional_packages(
+        "dolfin", "/usr/lib/petsc/lib/python3/dist-packages/dolfin/__init__.py", dependencies_import_name, [True]
+    )
