diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
index 5723c4c3..2cecd03b 100644
--- a/RECIPE-API-CHANGELOG.md
+++ b/RECIPE-API-CHANGELOG.md
@@ -1082,3 +1082,15 @@ To prevent this new path is separated also by distro and kernel values.
 
 This change will influence on build artifacts location and should be taken
 into account by downstreams.
+
+### Move kernel and DTBs deployment from image recipe to kernel related one
+
+To prevent parallel conflicting artifacts deployment from the same kernel
+used by different images, move do_copy_boot_files() task logic from the image
+recipe to the separate one, which is once-per-kernel. With this aproach the
+deployment of any kernel artifacts will be performed only once per kernel.
+
+To left previous kernel image path per-image symlinks are now used.
+
+This deployment is implemented as separated recipe to be compatible both with
+custom and distro kernel types.
diff --git a/meta/classes-recipe/image.bbclass b/meta/classes-recipe/image.bbclass
index 26a4ec06..a86ee443 100644
--- a/meta/classes-recipe/image.bbclass
+++ b/meta/classes-recipe/image.bbclass
@@ -1,5 +1,7 @@
 # This software is a part of Isar.
-# Copyright (C) 2015-2017 ilbers GmbH
+# Copyright (C) 2015-2026 ilbers GmbH
+#
+# SPDX-License-Identifier: MIT
 
 # Make workdir and stamps machine-specific without changing common PN target
 WORKDIR = "${TMPDIR}/work/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/${PV}-${PR}"
@@ -9,7 +11,6 @@ STAMPCLEAN = "${STAMPS_DIR}/${DISTRO}-${DISTRO_ARCH}/${PN}-${MACHINE}/*-*"
 
 # Sstate also needs to be machine-specific
 SSTATE_MANIFESTS = "${TMPDIR}/sstate-control/${MACHINE}-${DISTRO}-${DISTRO_ARCH}"
-SSTATETASKS += "do_copy_boot_files"
 
 IMAGE_INSTALL ?= ""
 IMAGE_FSTYPES ?= "ext4"
@@ -381,37 +382,21 @@ INITRD_IMG = "${PP_DEPLOY}/${INITRD_DEPLOY_FILE}"
 # only one dtb file supported, pick the first
 DTB_IMG = "${PP_DEPLOY}/${@(d.getVar('DTB_FILES').split() or [''])[0]}"
 
-do_copy_boot_files[cleandirs] += "${DEPLOYDIR}"
-do_copy_boot_files[sstate-inputdirs] = "${DEPLOYDIR}"
-do_copy_boot_files[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}"
-do_copy_boot_files[network] = "${TASK_USE_SUDO}"
+python() {
+    if d.getVar('DTB_FILES'):
+        d.appendVarFlag("do_copy_boot_files", "depends", "kernel-deploy-${KERNEL_NAME}:do_deploy")
+}
+
+# Associate kernel with image by symlinks
+do_copy_boot_files[dirs] += "${DEPLOY_DIR_IMAGE}"
 do_copy_boot_files() {
-    kernel="$(realpath -q '${IMAGE_ROOTFS}'/vmlinu[xz])"
-    if [ ! -f "$kernel" ]; then
-        kernel="$(realpath -q '${IMAGE_ROOTFS}'/boot/vmlinu[xz])"
-    fi
+    kernel="$(realpath -q '${DEPLOY_DIR_IMAGE}/${KERNEL_NAME}'-vmlinu[xz]*)"
     if [ -f "$kernel" ]; then
-        sudo cat "$kernel" > "${DEPLOYDIR}/${KERNEL_IMAGE}"
+        ln -sfr "$kernel" "${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGE}"
     fi
-
-    for file in ${DTB_FILES}; do
-        dtb="$(find '${IMAGE_ROOTFS}/usr/lib' -type f \
-                    -iwholename '*linux-image-*/'${file} | head -1)"
-
-        if [ -z "$dtb" -o ! -e "$dtb" ]; then
-            die "${file} not found"
-        fi
-
-        cp -f "$dtb" "${DEPLOYDIR}/"
-    done
 }
 addtask copy_boot_files before do_rootfs_postprocess after do_rootfs_install
 
-python do_copy_boot_files_setscene () {
-    sstate_setscene(d)
-}
-addtask do_copy_boot_files_setscene
-
 python do_image_tools() {
     """Virtual task"""
     pass
diff --git a/meta/recipes-kernel/kernel-deploy/kernel-deploy.bb b/meta/recipes-kernel/kernel-deploy/kernel-deploy.bb
new file mode 100644
index 00000000..32521148
--- /dev/null
+++ b/meta/recipes-kernel/kernel-deploy/kernel-deploy.bb
@@ -0,0 +1,53 @@
+# This software is a part of Isar.
+# Copyright (C) ilbers GmbH, 2026
+#
+# SPDX-License-Identifier: MIT
+
+inherit dpkg-raw
+
+MAINTAINER = "isar-users <isar-users@googlegroups.com>"
+
+PN:append = "-${KERNEL_NAME}"
+
+KERNEL_IMAGE_PKG ??= "${@ ("linux-image-" + d.getVar("KERNEL_NAME")) if d.getVar("KERNEL_NAME") else ""}"
+
+DEPENDS = "${KERNEL_IMAGE_PKG}"
+DEBIAN_BUILD_DEPENDS = "${KERNEL_IMAGE_PKG}"
+
+DPKG_ARCH = "${PACKAGE_ARCH}"
+
+do_prepare_build:append() {
+    dir=debian/${PN}/boot
+    cat <<EOF >> ${S}/debian/rules
+	mkdir -p ${dir}
+	realpath -q /boot/vmlinu[xz]
+	kernel="\$\$(realpath -q /vmlinu[xz])" && \
+	if [ ! -f "\$\${kernel}" ]; then kernel="\$\$(realpath -q /boot/vmlinu[xz])"; fi && \
+	if [ -f "\$\${kernel}" ]; then cp "\$\${kernel}" "${dir}/${KERNEL_NAME}-\$\$(basename \$\${kernel})"; fi
+EOF
+
+    for dtb in ${DTB_FILES}; do
+        dir=debian/${PN}/usr/lib/${PN}/$(dirname ${dtb})
+        cat <<EOF >> ${S}/debian/rules
+	mkdir -p ${dir}
+	find /usr/lib/linux-image* -path "*${dtb}" -print -exec cp {} ${dir} \;
+EOF
+    done
+}
+
+DTB_PACKAGE ??= "${PN}_${CHANGELOG_V}_${DISTRO_ARCH}.deb"
+
+do_deploy[dirs] = "${DEPLOY_DIR_IMAGE}"
+do_deploy[cleandirs] = "${WORKDIR}/deploy"
+do_deploy() {
+    dpkg --fsys-tarfile ${WORKDIR}/${DTB_PACKAGE} | \
+    tar --wildcards --extract --directory ${WORKDIR}/deploy ./boot ./usr/lib/${PN}
+    find ${WORKDIR}/deploy/boot -path "*vmlinu*" -print \
+            -exec cp {} ${DEPLOY_DIR_IMAGE}/ \;
+    for dtb in ${DTB_FILES}; do
+        mkdir -p ${DEPLOY_DIR_IMAGE}/$(dirname ${dtb})
+        find ${WORKDIR}/deploy/usr/lib/${PN} -path "*${dtb}" -print \
+            -exec cp {} ${DEPLOY_DIR_IMAGE}/${dtb} \;
+    done
+}
+addtask deploy before do_deploy_deb after do_dpkg_build
