diff --git a/lib/bb/fetch2/dependency.py b/lib/bb/fetch2/dependency.py
new file mode 100644
index 000000000..4acad8779
--- /dev/null
+++ b/lib/bb/fetch2/dependency.py
@@ -0,0 +1,175 @@
+# Copyright (C) 2024-2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+"""
+BitBake 'Fetch' mixin implementation for dependency specification files
+"""
+
+import tempfile
+import bb
+from bb.fetch2 import Fetch
+from bb.fetch2.git import Git
+from bb.fetch2.local import Local
+from bb.fetch2.wget import Wget
+from bb.utils import lockfile, unlockfile
+
+class DependencyMixin:
+    """Class to fetch all dependencies resolved via foreign function"""
+
+    def urldata_init(self, ud, d):
+        ud.type = ud.type.split("+")[-1] if "+" in ud.type else "file"
+        ud.url = ":".join((ud.type, ud.url.split(":", 1)[-1]))
+        super().urldata_init(ud, d)
+        ud.proxy = None
+
+    def _init_proxy(self, ud, d):
+        if ud.proxy:
+            return
+
+        urls = self.process_source(ud, d)
+        if urls:
+            ud.proxy = Fetch(urls, d)
+
+    @staticmethod
+    def _foreach_proxy_method(ud, handle, d):
+        """Call method for each dependency"""
+        returns = []
+        for proxy_url in ud.proxy.urls:
+            proxy_ud = ud.proxy.ud[proxy_url]
+            proxy_d = ud.proxy.d
+            proxy_ud.setup_localpath(proxy_d)
+            lf = lockfile(proxy_ud.lockfile)
+            returns.append(handle(proxy_ud.method, proxy_ud, proxy_d))
+            unlockfile(lf)
+        return returns
+
+    def verify_donestamp(self, ud, d):
+        """Verify the donestamp file"""
+        if not super().verify_donestamp(ud, d):
+            return False
+
+        self._init_proxy(ud, d)
+        def handle(m, ud, d):
+            return m.verify_donestamp(ud, d)
+        return all(self._foreach_proxy_method(ud, handle, d))
+
+    def update_donestamp(self, ud, d):
+        """Update the donestamp file"""
+        super().update_donestamp(ud, d)
+
+        self._init_proxy(ud, d)
+        def handle(m, ud, d):
+            m.update_donestamp(ud, d)
+        self._foreach_proxy_method(ud, handle, d)
+
+    def need_update(self, ud, d):
+        """Force a fetch, even if localpath exists ?"""
+        if super().need_update(ud, d):
+            return True
+
+        self._init_proxy(ud, d)
+        def handle(m, ud, d):
+            return m.need_update(ud, d)
+        return any(self._foreach_proxy_method(ud, handle, d))
+
+    def try_mirrors(self, fetch, ud, d, mirrors):
+        """Try to use a mirror"""
+        if not super().try_mirrors(fetch, ud, d, mirrors):
+            return False
+
+        self._init_proxy(ud, d)
+        def handle(m, ud, d):
+            return m.try_mirrors(fetch, ud, d, mirrors)
+        return all(self._foreach_proxy_method(ud, handle, d))
+
+    def download(self, ud, d):
+        """Fetch url"""
+        super().download(ud, d)
+        self._init_proxy(ud, d)
+        ud.proxy.download()
+
+    def unpack(self, ud, rootdir, d):
+        """Unpack the downloaded dependencies"""
+        super().unpack(ud, rootdir, d)
+        self._init_proxy(ud, d)
+        ud.proxy.unpack(ud.destdir)
+
+    def clean(self, ud, d):
+        """Clean any existing full or partial download"""
+        self._init_proxy(ud, d)
+        ud.proxy.clean()
+        super().clean(ud, d)
+
+    def done(self, ud, d):
+        """Is the download done ?"""
+        if not super().done(ud, d):
+            return False
+
+        self._init_proxy(ud, d)
+        def _handle(m, ud, d):
+            return m.done(ud, d)
+        return all(self._foreach_proxy_method(ud, _handle, d))
+
+class LocalDependency(DependencyMixin, Local):
+    """
+    Abstract class to fetch all dependencies from a local specification file
+    """
+
+    def process_source(self, ud, d):
+        return self.resolve_dependencies(ud, ud.localpath, d)
+
+class WgetDependency(DependencyMixin, Wget):
+    """
+    Abstract class to fetch all dependencies from a specification file inside an
+    archive
+    """
+
+    def process_source(self, ud, d):
+        with tempfile.TemporaryDirectory(dir=d.getVar('DL_DIR')) as tmpdir:
+            Wget.unpack(self, ud, tmpdir, d)
+            return self.resolve_dependencies(ud, ud.destdir, d)
+
+class GitDependency(DependencyMixin, Git):
+    """
+    Abstract class to fetch all dependencies from a specification file inside a
+    git repository
+    """
+
+    def process_source(self, ud, d):
+        with tempfile.TemporaryDirectory(dir=d.getVar('DL_DIR')) as tmpdir:
+            Git.unpack(self, ud, tmpdir, d)
+            return self.resolve_dependencies(ud, ud.destdir, d)
+
+def create_methods(type, mixin):
+    class SpecificLocalDependency(mixin, LocalDependency):
+        """
+        Specific class to fetch all dependencies from a local specification file
+        """
+
+        def supports(self, ud, d):
+            return ud.type == type
+
+    class SpecificWgetDependency(mixin, WgetDependency):
+        """
+        Specific class to fetch all dependencies from a specification file
+        inside an archive
+        """
+
+        def supports(self, ud, d):
+            return ud.type in [f"{type}+http", f"{type}+https"]
+
+    class SpecificGitDependency(mixin, GitDependency):
+        """
+        Specific class to fetch all dependencies from a specification file
+        inside a git repository
+        """
+
+        def supports(self, ud, d):
+            return ud.type == f"{type}+git"
+
+    return [
+        SpecificLocalDependency(),
+        SpecificWgetDependency(),
+        SpecificGitDependency()]
