diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 9c3d2d04d6a1..bd48b5358890 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -526,6 +526,8 @@ enum nft_bitwise_ops {
  * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops)
  * @NFTA_BITWISE_DATA: argument for non-boolean operations
  *                     (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_MREG: mask register (NLA_U32: nft_registers)
+ * @NFTA_BITWISE_XREG: xor register (NLA_U32: nft_registers)
  *
  * The bitwise expression supports boolean and shift operations.  It implements
  * the boolean operations by performing the following operation:
@@ -549,6 +551,8 @@ enum nft_bitwise_attributes {
 	NFTA_BITWISE_XOR,
 	NFTA_BITWISE_OP,
 	NFTA_BITWISE_DATA,
+	NFTA_BITWISE_MREG,
+	NFTA_BITWISE_XREG,
 	__NFTA_BITWISE_MAX
 };
 #define NFTA_BITWISE_MAX	(__NFTA_BITWISE_MAX - 1)
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index bc37d6c59db4..8877b50fed78 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -15,23 +15,47 @@
 #include <net/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables_offload.h>
 
+enum nft_bitwise_flags {
+	NFT_BITWISE_MASK_REG = 1,
+	NFT_BITWISE_XOR_REG,
+};
+
 struct nft_bitwise {
 	enum nft_registers	sreg:8;
 	enum nft_registers	dreg:8;
 	enum nft_bitwise_ops	op:8;
 	u8			len;
-	struct nft_data		mask;
-	struct nft_data		xor;
+	enum nft_bitwise_flags	flags;
 	struct nft_data		data;
+	union {
+		struct nft_data         data;
+		enum nft_registers      reg:8;
+	} mask;
+	union {
+		struct nft_data         data;
+		enum nft_registers      reg:8;
+	} xor;
 };
 
 static void nft_bitwise_eval_bool(u32 *dst, const u32 *src,
-				  const struct nft_bitwise *priv)
+				  const struct nft_bitwise *priv,
+				  struct nft_regs *regs)
 {
+	const u32 *mask, *xor;
 	unsigned int i;
 
+	if (priv->flags & NFT_BITWISE_MASK_REG)
+		mask = &regs->data[priv->mask.reg];
+	else
+		mask = priv->mask.data.data;
+
+	if (priv->flags & NFT_BITWISE_XOR_REG)
+		xor = &regs->data[priv->xor.reg];
+	else
+		xor = priv->xor.data.data;
+
 	for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++)
-		dst[i] = (src[i] & priv->mask.data[i]) ^ priv->xor.data[i];
+		dst[i] = (src[i] & mask[i]) ^ xor[i];
 }
 
 static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src,
@@ -69,7 +93,7 @@ void nft_bitwise_eval(const struct nft_expr *expr,
 
 	switch (priv->op) {
 	case NFT_BITWISE_BOOL:
-		nft_bitwise_eval_bool(dst, src, priv);
+		nft_bitwise_eval_bool(dst, src, priv, regs);
 		break;
 	case NFT_BITWISE_LSHIFT:
 		nft_bitwise_eval_lshift(dst, src, priv);
@@ -88,6 +112,8 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
 	[NFTA_BITWISE_XOR]	= { .type = NLA_NESTED },
 	[NFTA_BITWISE_OP]	= { .type = NLA_U32 },
 	[NFTA_BITWISE_DATA]	= { .type = NLA_NESTED },
+	[NFTA_BITWISE_MREG]	= { .type = NLA_U32 },
+	[NFTA_BITWISE_XREG]	= { .type = NLA_U32 },
 };
 
 static int nft_bitwise_init_bool(struct nft_bitwise *priv,
@@ -99,33 +125,57 @@ static int nft_bitwise_init_bool(struct nft_bitwise *priv,
 	if (tb[NFTA_BITWISE_DATA])
 		return -EINVAL;
 
-	if (!tb[NFTA_BITWISE_MASK] ||
-	    !tb[NFTA_BITWISE_XOR])
+	if ((!tb[NFTA_BITWISE_MASK] && !tb[NFTA_BITWISE_MREG]) ||
+	    (tb[NFTA_BITWISE_MASK] && tb[NFTA_BITWISE_MREG]))
 		return -EINVAL;
 
-	err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &mask,
-			    tb[NFTA_BITWISE_MASK]);
-	if (err < 0)
-		return err;
-	if (mask.type != NFT_DATA_VALUE || mask.len != priv->len) {
-		err = -EINVAL;
-		goto err1;
+	if ((!tb[NFTA_BITWISE_XOR] && !tb[NFTA_BITWISE_XREG]) ||
+	    (tb[NFTA_BITWISE_XOR] && tb[NFTA_BITWISE_XREG]))
+		return -EINVAL;
+
+	if (tb[NFTA_BITWISE_MASK]) {
+		err = nft_data_init(NULL, &priv->mask.data,
+				    sizeof(priv->mask.data), &mask,
+				    tb[NFTA_BITWISE_MASK]);
+		if (err < 0)
+			return err;
+		if (mask.type != NFT_DATA_VALUE || mask.len != priv->len) {
+			err = -EINVAL;
+			goto err1;
+		}
+	} else {
+		priv->mask.reg = nft_parse_register(tb[NFTA_BITWISE_MREG]);
+		err = nft_validate_register_load(priv->mask.reg, priv->len);
+		if (err < 0)
+			return err;
+		priv->flags |= NFT_BITWISE_MASK_REG;
 	}
 
-	err = nft_data_init(NULL, &priv->xor, sizeof(priv->xor), &xor,
-			    tb[NFTA_BITWISE_XOR]);
-	if (err < 0)
-		goto err1;
-	if (xor.type != NFT_DATA_VALUE || xor.len != priv->len) {
-		err = -EINVAL;
-		goto err2;
+	if (tb[NFTA_BITWISE_XOR]) {
+		err = nft_data_init(NULL, &priv->xor.data,
+				    sizeof(priv->xor.data), &xor,
+				    tb[NFTA_BITWISE_XOR]);
+		if (err < 0)
+			goto err1;
+		if (xor.type != NFT_DATA_VALUE || xor.len != priv->len) {
+			err = -EINVAL;
+			goto err2;
+		}
+	} else {
+		priv->xor.reg = nft_parse_register(tb[NFTA_BITWISE_XREG]);
+		err = nft_validate_register_load(priv->xor.reg, priv->len);
+		if (err < 0)
+			return err;
+		priv->flags |= NFT_BITWISE_XOR_REG;
 	}
 
 	return 0;
 err2:
-	nft_data_release(&priv->xor, xor.type);
+	if (tb[NFTA_BITWISE_XOR])
+		nft_data_release(&priv->xor.data, xor.type);
 err1:
-	nft_data_release(&priv->mask, mask.type);
+	if (tb[NFTA_BITWISE_MASK])
+		nft_data_release(&priv->mask.data, mask.type);
 	return err;
 }
 
@@ -215,13 +265,23 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
 static int nft_bitwise_dump_bool(struct sk_buff *skb,
 				 const struct nft_bitwise *priv)
 {
-	if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
-			  NFT_DATA_VALUE, priv->len) < 0)
-		return -1;
+	if (priv->flags & NFT_BITWISE_MASK_REG) {
+		if (nft_dump_register(skb, NFTA_BITWISE_MREG, priv->mask.reg))
+			return -1;
+	} else {
+		if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask.data,
+				  NFT_DATA_VALUE, priv->len) < 0)
+			return -1;
+	}
 
-	if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
-			  NFT_DATA_VALUE, priv->len) < 0)
-		return -1;
+	if (priv->flags & NFT_BITWISE_XOR_REG) {
+		if (nft_dump_register(skb, NFTA_BITWISE_XREG, priv->xor.reg))
+			return -1;
+	} else {
+		if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor.data,
+				  NFT_DATA_VALUE, priv->len) < 0)
+			return -1;
+	}
 
 	return 0;
 }
