diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index 08f87cb9a8..2f582caaee 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -33,6 +33,13 @@ struct TPMState {
 
 #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
 
+#define TPM_STANDARD_CMDLINE_OPTS \
+    { \
+        .name = "type", \
+        .type = QEMU_OPT_STRING, \
+        .help = "Type of TPM backend", \
+    }
+
 struct tpm_req_hdr {
     uint16_t tag;
     uint32_t len;
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index ce74e97043..56e9e0f8a2 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -488,8 +488,24 @@ static void tpm_passthrough_destroy(TPMBackend *tb)
     g_free(tpm_pt->tpm_dev);
 }
 
+static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
+    TPM_STANDARD_CMDLINE_OPTS,
+    {
+        .name = "cancel-path",
+        .type = QEMU_OPT_STRING,
+        .help = "Sysfs file entry for canceling TPM commands",
+    },
+    {
+        .name = "path",
+        .type = QEMU_OPT_STRING,
+        .help = "Path to TPM device on the host",
+    },
+    { /* end of list */ },
+};
+
 static const TPMDriverOps tpm_passthrough_driver = {
     .type                     = TPM_TYPE_PASSTHROUGH,
+    .opts                     = tpm_passthrough_cmdline_opts,
     .desc                     = tpm_passthrough_create_desc,
     .create                   = tpm_passthrough_create,
     .destroy                  = tpm_passthrough_destroy,
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 466787453d..825f33bdc3 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -65,6 +65,7 @@ typedef struct TPMSizedBuffer {
 
 struct TPMDriverOps {
     enum TpmType type;
+    const QemuOptDesc *opts;
     /* get a descriptive text of the backend to display to the user */
     const char *(*desc)(void);
 
diff --git a/tpm.c b/tpm.c
index c91da43cf1..f13c9bc80c 100644
--- a/tpm.c
+++ b/tpm.c
@@ -159,6 +159,14 @@ static int configure_tpm(QemuOpts *opts)
         return 1;
     }
 
+    /* validate backend specific opts */
+    qemu_opts_validate(opts, be->opts, &local_err);
+    if (error_is_set(&local_err)) {
+        qerror_report_err(local_err);
+        error_free(local_err);
+        return 1;
+    }
+
     drv = be->create(opts, id);
     if (!drv) {
         return 1;
diff --git a/vl.c b/vl.c
index 6caa5f4272..2e0d1a744c 100644
--- a/vl.c
+++ b/vl.c
@@ -502,21 +502,7 @@ static QemuOptsList qemu_tpmdev_opts = {
     .implied_opt_name = "type",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_tpmdev_opts.head),
     .desc = {
-        {
-            .name = "type",
-            .type = QEMU_OPT_STRING,
-            .help = "Type of TPM backend",
-        },
-        {
-            .name = "cancel-path",
-            .type = QEMU_OPT_STRING,
-            .help = "Sysfs file entry for canceling TPM commands",
-        },
-        {
-            .name = "path",
-            .type = QEMU_OPT_STRING,
-            .help = "Path to TPM device on the host",
-        },
+        /* options are defined in the TPM backends */
         { /* end of list */ }
     },
 };