diff --git a/include/rule.h b/include/rule.h
index 909ff36..bed9c2a 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -193,6 +193,7 @@ struct chain {
 	struct list_head	rules;
 };
 
+extern int chain_std_prio_lookup(const char *std_prio_name);
 extern const char *chain_type_name_lookup(const char *name);
 extern const char *chain_hookname_lookup(const char *name);
 extern struct chain *chain_alloc(const char *name);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 98bfeba..d753fd9 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -21,6 +21,7 @@
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
 #include <linux/netfilter/nf_nat.h>
 #include <linux/netfilter/nf_log.h>
+#include <linux/netfilter_ipv4.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
 #include <libnftnl/common.h>
@@ -182,6 +183,8 @@ int nft_lex(void *, void *, void *);
 %token AT			"@"
 %token VMAP			"vmap"
 
+%token PLUS			"+"
+
 %token INCLUDE			"include"
 %token DEFINE			"define"
 %token REDEFINE			"redefine"
@@ -521,7 +524,7 @@ int nft_lex(void *, void *, void *);
 %destructor { handle_free(&$$); } table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
 %type <handle>			set_spec setid_spec set_identifier flowtable_identifier obj_spec objid_spec obj_identifier
 %destructor { handle_free(&$$); } set_spec setid_spec set_identifier obj_spec objid_spec obj_identifier
-%type <val>			family_spec family_spec_explicit chain_policy prio_spec
+%type <val>			family_spec family_spec_explicit chain_policy prio_spec standard_prio
 
 %type <string>			dev_spec quota_unit
 %destructor { xfree($$); }	dev_spec quota_unit
@@ -1794,8 +1797,23 @@ hook_spec		:	TYPE		STRING		HOOK		STRING		dev_spec	PRIORITY	prio_spec
 			}
 			;
 
-prio_spec		:	NUM			{ $$ = $1; }
-			|	DASH	NUM		{ $$ = -$2; }
+prio_spec		:	NUM                 { $$ =   $1; }
+			|	DASH	NUM             { $$ =  -$2; }
+			|	standard_prio
+			|	standard_prio PLUS NUM { $$ = $1 + $3; }
+			|	standard_prio DASH NUM { $$ = $1 - $3; }
+			;
+
+standard_prio	:	STRING
+			{
+				int tmp = chain_std_prio_lookup($1);
+				if (tmp == NF_IP_PRI_LAST) {
+					erec_queue(error(&@$, "priority name '%s' is invalid", $1),
+						   state->msgs);
+					YYERROR;
+				}
+				$$ = tmp;
+			}
 			;
 
 dev_spec		:	DEVICE	STRING		{ $$ = $2; }
diff --git a/src/rule.c b/src/rule.c
index 56b956a..11d11b1 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -28,6 +28,7 @@
 #include <netinet/ip.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_arp.h>
+#include <linux/netfilter_ipv4.h>
 
 void handle_free(struct handle *h)
 {
@@ -769,6 +770,56 @@ const char *chain_policy2str(uint32_t policy)
 	return "unknown";
 }
 
+struct chain_prio_tag{
+	int val;
+	const char *str;
+};
+
+const static struct chain_prio_tag chain_std_prios[] = {
+	{ NF_IP_PRI_RAW,      "raw" },
+	{ NF_IP_PRI_MANGLE,   "mangle" },
+	{ NF_IP_PRI_NAT_DST,  "dnat" },
+	{ NF_IP_PRI_FILTER,   "filter" },
+	{ NF_IP_PRI_SECURITY, "security" },
+	{ NF_IP_PRI_NAT_SRC,  "snat" },
+};
+
+int chain_std_prio_lookup(const char *std_prio_name) {
+	long unsigned int i;
+
+	for (i = 0; i < sizeof(chain_std_prios) / sizeof(struct chain_prio_tag); ++i) {
+		if (!strcmp(chain_std_prios[i].str, std_prio_name))
+			return chain_std_prios[i].val;
+	}
+	return NF_IP_PRI_LAST;
+}
+
+static const char *chain_prio2str(int prio)
+{
+	static char ret[256];
+	char offstr[20];
+	const int reach = 10;
+	size_t i;
+
+	ret[0] = 0;
+	offstr[0] = 0;
+	for (i = 0; i < sizeof(chain_std_prios) / sizeof(struct chain_prio_tag); ++i) {
+		const int sdt_prio = chain_std_prios[i].val;
+		const char *sdt_prio_str = chain_std_prios[i].str;
+		if (prio >= sdt_prio - reach && prio <= sdt_prio + reach) {
+			int offset = prio - sdt_prio;
+			if (offset != 0) {
+				snprintf(offstr, sizeof(offstr), " %c %d",
+					 offset > 0 ? '+' : '-', abs(offset));
+			}
+			sprintf(ret, "%s%s", sdt_prio_str, offstr);
+			return ret;
+		}
+	}
+	sprintf(ret, "%d", prio);
+	return ret;
+}
+
 static void chain_print_declaration(const struct chain *chain,
 				    struct output_ctx *octx)
 {
@@ -781,8 +832,8 @@ static void chain_print_declaration(const struct chain *chain,
 			  hooknum2str(chain->handle.family, chain->hooknum));
 		if (chain->dev != NULL)
 			nft_print(octx, " device %s", chain->dev);
-		nft_print(octx, " priority %d; policy %s;\n",
-			  chain->priority, chain_policy2str(chain->policy));
+		nft_print(octx, " priority %s; policy %s;\n",
+			  chain_prio2str(chain->priority), chain_policy2str(chain->policy));
 	}
 }
 
@@ -806,9 +857,9 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
 		  chain->handle.table.name, chain->handle.chain.name);
 
 	if (chain->flags & CHAIN_F_BASECHAIN) {
-		nft_print(octx, " { type %s hook %s priority %d; policy %s; }",
+		nft_print(octx, " { type %s hook %s priority %s; policy %s; }",
 			  chain->type, chain->hookstr,
-			  chain->priority, chain_policy2str(chain->policy));
+			  chain_prio2str(chain->priority), chain_policy2str(chain->policy));
 	}
 	if (octx->handle > 0)
 		nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
diff --git a/src/scanner.l b/src/scanner.l
index ed01b5e..4fb3a39 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -232,6 +232,8 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "="			{ return '='; }
 "vmap"			{ return VMAP; }
 
+"+" 		{ return PLUS; }
+
 "include"		{ return INCLUDE; }
 "define"		{ return DEFINE; }
 "redefine"		{ return REDEFINE; }
