diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fa11ee3df5..ab8a6c00c3 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1688,6 +1688,7 @@ virSecurityManagerRestoreHostdevLabel;
 virSecurityManagerRestoreImageLabel;
 virSecurityManagerRestoreInputLabel;
 virSecurityManagerRestoreMemoryLabel;
+virSecurityManagerRestoreNetdevLabel;
 virSecurityManagerRestoreSavedStateLabel;
 virSecurityManagerRestoreTPMLabels;
 virSecurityManagerSetAllLabel;
@@ -1699,6 +1700,7 @@ virSecurityManagerSetImageFDLabel;
 virSecurityManagerSetImageLabel;
 virSecurityManagerSetInputLabel;
 virSecurityManagerSetMemoryLabel;
+virSecurityManagerSetNetdevLabel;
 virSecurityManagerSetProcessLabel;
 virSecurityManagerSetSavedStateLabel;
 virSecurityManagerSetSocketLabel;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 64580b573b..9c16ab4567 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1203,6 +1203,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
     g_autofree char *netdev_name = NULL;
     g_autoptr(virConnect) conn = NULL;
     virErrorPtr save_err = NULL;
+    bool teardownlabel = false;
 
     /* If appropriate, grab a physical device from the configured
      * network's pool of devices, or resolve bridge device name
@@ -1343,6 +1344,9 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
                                                    &net->ifname) < 0)
             goto cleanup;
 
+        if (qemuSecuritySetNetdevLabel(driver, vm, net) < 0)
+            goto cleanup;
+        teardownlabel = true;
         break;
 
     case VIR_DOMAIN_NET_TYPE_USER:
@@ -1559,6 +1563,10 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
             qemuDomainNetDeviceVportRemove(net);
         }
 
+        if (teardownlabel &&
+            qemuSecurityRestoreNetdevLabel(driver, vm, net) < 0)
+            VIR_WARN("Unable to restore network device labelling on hotplug fail");
+
         /* we had potentially pre-added the device to the domain
          * device lists, if so we need to remove it (from def->nets
          * and/or def->hostdevs) on failure
@@ -4803,6 +4811,11 @@ qemuDomainRemoveNetDevice(virQEMUDriver *driver,
                          cfg->stateDir));
     }
 
+    if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
+        if (qemuSecurityRestoreNetdevLabel(driver, vm, net) < 0)
+            VIR_WARN("Unable to restore security label on vhostuser char device");
+    }
+
     qemuDomainNetDeviceVportRemove(net);
 
     if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
diff --git a/src/qemu/qemu_security.c b/src/qemu/qemu_security.c
index e582a66071..19d957dd4b 100644
--- a/src/qemu/qemu_security.c
+++ b/src/qemu/qemu_security.c
@@ -439,6 +439,65 @@ qemuSecurityRestoreChardevLabel(virQEMUDriver *driver,
     return ret;
 }
 
+int
+qemuSecuritySetNetdevLabel(virQEMUDriver *driver,
+                           virDomainObj *vm,
+                           virDomainNetDef *net)
+{
+    int ret = -1;
+    qemuDomainObjPrivate *priv = vm->privateData;
+    pid_t pid = -1;
+
+    if (qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
+        pid = vm->pid;
+
+    if (virSecurityManagerTransactionStart(driver->securityManager) < 0)
+        goto cleanup;
+
+    if (virSecurityManagerSetNetdevLabel(driver->securityManager,
+                                         vm->def, net) < 0)
+        goto cleanup;
+
+    if (virSecurityManagerTransactionCommit(driver->securityManager,
+                                            pid, priv->rememberOwner) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    virSecurityManagerTransactionAbort(driver->securityManager);
+    return ret;
+}
+
+
+int
+qemuSecurityRestoreNetdevLabel(virQEMUDriver *driver,
+                               virDomainObj *vm,
+                               virDomainNetDef *net)
+{
+    int ret = -1;
+    qemuDomainObjPrivate *priv = vm->privateData;
+    pid_t pid = -1;
+
+    if (qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT))
+        pid = vm->pid;
+
+    if (virSecurityManagerTransactionStart(driver->securityManager) < 0)
+        goto cleanup;
+
+    if (virSecurityManagerRestoreNetdevLabel(driver->securityManager,
+                                             vm->def, net) < 0)
+        goto cleanup;
+
+    if (virSecurityManagerTransactionCommit(driver->securityManager,
+                                            pid, priv->rememberOwner) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    virSecurityManagerTransactionAbort(driver->securityManager);
+    return ret;
+}
+
 
 /*
  * qemuSecurityStartVhostUserGPU:
diff --git a/src/qemu/qemu_security.h b/src/qemu/qemu_security.h
index 4c3d81e4b5..8b26ea3f99 100644
--- a/src/qemu/qemu_security.h
+++ b/src/qemu/qemu_security.h
@@ -79,6 +79,14 @@ int qemuSecurityRestoreChardevLabel(virQEMUDriver *driver,
                                     virDomainObj *vm,
                                     virDomainChrDef *chr);
 
+int qemuSecuritySetNetdevLabel(virQEMUDriver *driver,
+                               virDomainObj *vm,
+                               virDomainNetDef *net);
+
+int qemuSecurityRestoreNetdevLabel(virQEMUDriver *driver,
+                                   virDomainObj *vm,
+                                   virDomainNetDef *net);
+
 int qemuSecurityStartVhostUserGPU(virQEMUDriver *driver,
                                   virDomainObj *vm,
                                   virCommand *cmd,
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index 84363015dc..d942ea5005 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -1053,6 +1053,64 @@ AppArmorRestoreChardevLabel(virSecurityManager *mgr,
     return reload_profile(mgr, def, NULL, false);
 }
 
+static int
+AppArmorSetNetdevLabel(virSecurityManager *mgr,
+                       virDomainDef *def,
+                       virDomainNetDef *net)
+{
+    int ret = -1;
+    virSecurityLabelDef *secdef;
+    virDomainChrSourceDef *dev_source;
+    virDomainNetType actualType;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+    if (!secdef)
+        return 0;
+
+    actualType = virDomainNetGetActualType(net);
+    if (actualType != VIR_DOMAIN_NET_TYPE_VHOSTUSER)
+        return 0;
+
+    dev_source = net->data.vhostuser;
+    switch ((virDomainChrType)dev_source->type) {
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+        ret = reload_profile(mgr, def, dev_source->data.file.path, true);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+    case VIR_DOMAIN_CHR_TYPE_PTY:
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
+    case VIR_DOMAIN_CHR_TYPE_NULL:
+    case VIR_DOMAIN_CHR_TYPE_VC:
+    case VIR_DOMAIN_CHR_TYPE_STDIO:
+    case VIR_DOMAIN_CHR_TYPE_UDP:
+    case VIR_DOMAIN_CHR_TYPE_TCP:
+    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
+    case VIR_DOMAIN_CHR_TYPE_NMDM:
+    case VIR_DOMAIN_CHR_TYPE_LAST:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static int
+AppArmorRestoreNetdevLabel(virSecurityManager *mgr,
+                           virDomainDef *def,
+                           virDomainNetDef *net G_GNUC_UNUSED)
+{
+    virSecurityLabelDef *secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+    if (!secdef)
+        return 0;
+
+    return reload_profile(mgr, def, NULL, false);
+}
+
 static int
 AppArmorSetPathLabel(virSecurityManager *mgr,
                            virDomainDef *def,
@@ -1168,6 +1226,9 @@ virSecurityDriver virAppArmorSecurityDriver = {
     .domainSetSecurityChardevLabel      = AppArmorSetChardevLabel,
     .domainRestoreSecurityChardevLabel  = AppArmorRestoreChardevLabel,
 
+    .domainSetSecurityNetdevLabel       = AppArmorSetNetdevLabel,
+    .domainRestoreSecurityNetdevLabel   = AppArmorRestoreNetdevLabel,
+
     .domainSetSecurityImageFDLabel      = AppArmorSetFDLabel,
     .domainSetSecurityTapFDLabel        = AppArmorSetFDLabel,
 
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
index 07f8def3d3..a1fc23be38 100644
--- a/src/security/security_driver.h
+++ b/src/security/security_driver.h
@@ -157,6 +157,12 @@ typedef int (*virSecurityDomainSetTPMLabels) (virSecurityManager *mgr,
                                               virDomainDef *def);
 typedef int (*virSecurityDomainRestoreTPMLabels) (virSecurityManager *mgr,
                                                   virDomainDef *def);
+typedef int (*virSecurityDomainSetNetdevLabel) (virSecurityManager *mgr,
+                                                virDomainDef *def,
+                                                virDomainNetDef *net);
+typedef int (*virSecurityDomainRestoreNetdevLabel) (virSecurityManager *mgr,
+                                                    virDomainDef *def,
+                                                    virDomainNetDef *net);
 
 
 struct _virSecurityDriver {
@@ -224,6 +230,9 @@ struct _virSecurityDriver {
 
     virSecurityDomainSetTPMLabels domainSetSecurityTPMLabels;
     virSecurityDomainRestoreTPMLabels domainRestoreSecurityTPMLabels;
+
+    virSecurityDomainSetNetdevLabel domainSetSecurityNetdevLabel;
+    virSecurityDomainRestoreNetdevLabel domainRestoreSecurityNetdevLabel;
 };
 
 virSecurityDriver *virSecurityDriverLookup(const char *name,
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
index 9906c1691d..d8a03a19cb 100644
--- a/src/security/security_manager.c
+++ b/src/security/security_manager.c
@@ -1297,6 +1297,44 @@ virSecurityManagerRestoreTPMLabels(virSecurityManager *mgr,
 }
 
 
+int
+virSecurityManagerSetNetdevLabel(virSecurityManager *mgr,
+                                 virDomainDef *vm,
+                                 virDomainNetDef *net)
+{
+    int ret;
+
+    if (mgr->drv->domainSetSecurityNetdevLabel) {
+        virObjectLock(mgr);
+        ret = mgr->drv->domainSetSecurityNetdevLabel(mgr, vm, net);
+        virObjectUnlock(mgr);
+
+        return ret;
+    }
+
+    return 0;
+}
+
+
+int
+virSecurityManagerRestoreNetdevLabel(virSecurityManager *mgr,
+                                     virDomainDef *vm,
+                                     virDomainNetDef *net)
+{
+    int ret;
+
+    if (mgr->drv->domainRestoreSecurityNetdevLabel) {
+        virObjectLock(mgr);
+        ret = mgr->drv->domainRestoreSecurityNetdevLabel(mgr, vm, net);
+        virObjectUnlock(mgr);
+
+        return ret;
+    }
+
+    return 0;
+}
+
+
 static int
 cmpstringp(const void *p1, const void *p2)
 {
diff --git a/src/security/security_manager.h b/src/security/security_manager.h
index 57047ccb13..59020b1475 100644
--- a/src/security/security_manager.h
+++ b/src/security/security_manager.h
@@ -220,6 +220,14 @@ int virSecurityManagerSetTPMLabels(virSecurityManager *mgr,
 int virSecurityManagerRestoreTPMLabels(virSecurityManager *mgr,
                                        virDomainDef *vm);
 
+int virSecurityManagerSetNetdevLabel(virSecurityManager *mgr,
+                                     virDomainDef *vm,
+                                     virDomainNetDef *net);
+
+int virSecurityManagerRestoreNetdevLabel(virSecurityManager *mgr,
+                                         virDomainDef *vm,
+                                         virDomainNetDef *net);
+
 typedef struct _virSecurityManagerMetadataLockState virSecurityManagerMetadataLockState;
 struct _virSecurityManagerMetadataLockState {
     size_t nfds; /* Captures size of both @fds and @paths */
diff --git a/src/security/security_stack.c b/src/security/security_stack.c
index f7a9ed1e33..3c2239910a 100644
--- a/src/security/security_stack.c
+++ b/src/security/security_stack.c
@@ -963,6 +963,55 @@ virSecurityStackRestoreTPMLabels(virSecurityManager *mgr,
 }
 
 
+static int
+virSecurityStackDomainSetNetdevLabel(virSecurityManager *mgr,
+                                     virDomainDef *def,
+                                     virDomainNetDef *net)
+{
+    virSecurityStackData *priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItem *item = priv->itemsHead;
+
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetNetdevLabel(item->securityManager, def, net) < 0)
+            goto rollback;
+    }
+
+    return 0;
+
+ rollback:
+    for (item = item->prev; item; item = item->prev) {
+        if (virSecurityManagerRestoreNetdevLabel(item->securityManager,
+                                                 def, net) < 0) {
+            VIR_WARN("Unable to restore netdev label after failed set label "
+                     "call virDriver=%s driver=%s domain=%s",
+                     virSecurityManagerGetVirtDriver(mgr),
+                     virSecurityManagerGetDriver(item->securityManager),
+                     def->name);
+        }
+    }
+    return -1;
+}
+
+
+static int
+virSecurityStackDomainRestoreNetdevLabel(virSecurityManager *mgr,
+                                         virDomainDef *def,
+                                         virDomainNetDef *net)
+{
+    virSecurityStackData *priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItem *item = priv->itemsHead;
+    int rc = 0;
+
+    for (; item; item = item->next) {
+        if (virSecurityManagerRestoreNetdevLabel(item->securityManager,
+                                                 def, net) < 0)
+            rc = -1;
+    }
+
+    return rc;
+}
+
+
 virSecurityDriver virSecurityDriverStack = {
     .privateDataLen                     = sizeof(virSecurityStackData),
     .name                               = "stack",
@@ -1028,4 +1077,7 @@ virSecurityDriver virSecurityDriverStack = {
 
     .domainSetSecurityTPMLabels         = virSecurityStackSetTPMLabels,
     .domainRestoreSecurityTPMLabels     = virSecurityStackRestoreTPMLabels,
+
+    .domainSetSecurityNetdevLabel      = virSecurityStackDomainSetNetdevLabel,
+    .domainRestoreSecurityNetdevLabel  = virSecurityStackDomainRestoreNetdevLabel,
 };