diff --git a/namesys/dns.go b/namesys/dns.go
index 96147534a84..6f1468a5704 100644
--- a/namesys/dns.go
+++ b/namesys/dns.go
@@ -41,6 +41,11 @@ func (r *DNSResolver) ResolveN(ctx context.Context, name string, depth int) (pat
 	return resolve(ctx, r, name, depth, "/ipns/")
 }
 
+type lookupRes struct {
+	path path.Path
+	error error
+}
+
 // resolveOnce implements resolver.
 // TXT records for a given domain name should contain a b58
 // encoded multihash.
@@ -50,24 +55,46 @@ func (r *DNSResolver) resolveOnce(ctx context.Context, name string) (path.Path,
 	if !isd.IsDomain(segments[0]) {
 		return "", errors.New("not a valid domain name")
 	}
-
 	log.Infof("DNSResolver resolving %s", segments[0])
-	txt, err := r.lookupTXT(segments[0])
+
+	prefixes := []string{"", "_dnslink."}
+
+	resChan := make(chan lookupRes)
+
+	for _, prefix := range prefixes {
+		go workDomain(r, prefix + segments[0], resChan)
+	}
+
+	for active := len(prefixes); active > 0; active-- {
+		res := <- resChan
+		if res.error == nil {
+			return res.path, nil
+		}
+	}
+
+	return "", ErrResolveFailed
+}
+
+func workDomain(r *DNSResolver, name string, res chan lookupRes) {
+	txt, err := r.lookupTXT(name)
+
 	if err != nil {
-		return "", err
+		res <- lookupRes{"", err}
+		return
 	}
 
 	for _, t := range txt {
 		p, err := parseEntry(t)
 		if err == nil {
 			if len(segments) > 1 {
-				return path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[1])
+				res <- lookupRes{path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[1])}
+			} else {
+				res <-lookupRes{p, nil}
 			}
-			return p, nil
+			return
 		}
 	}
-
-	return "", ErrResolveFailed
+	res <- lookupRes{"", ErrResolveFailed}
 }
 
 func parseEntry(txt string) (path.Path, error) {
diff --git a/namesys/dns_test.go b/namesys/dns_test.go
index 27b3883db78..0cb83eed348 100644
--- a/namesys/dns_test.go
+++ b/namesys/dns_test.go
@@ -65,6 +65,9 @@ func newMockDNS() *mockDNS {
 			"ipfs.example.com": []string{
 				"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
 			},
+			"_dnslink.dipfs.example.com": []string{
+				"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
+			},
 			"dns1.example.com": []string{
 				"dnslink=/ipns/ipfs.example.com",
 			},
@@ -85,6 +88,12 @@ func newMockDNS() *mockDNS {
 			"loop2.example.com": []string{
 				"dnslink=/ipns/loop1.example.com",
 			},
+			"_dnslink.dloop1.example.com": []string{
+				"dnslink=/ipns/loop2.example.com",
+			},
+			"_dnslink.dloop2.example.com": []string{
+				"dnslink=/ipns/loop1.example.com",
+			},
 			"bad.example.com": []string{
 				"dnslink=",
 			},
@@ -100,6 +109,12 @@ func newMockDNS() *mockDNS {
 			"withtrailingrec.example.com": []string{
 				"dnslink=/ipns/withtrailing.example.com/segment/",
 			},
+			"double.example.com": []string{
+				"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
+			},
+			"_dnslink.double.example.com": []string{
+				"dnslink=/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD",
+			},
 		},
 	}
 }
@@ -109,6 +124,7 @@ func TestDNSResolution(t *testing.T) {
 	r := &DNSResolver{lookupTXT: mock.lookupTXT}
 	testResolution(t, r, "multihash.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
 	testResolution(t, r, "ipfs.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
+	testResolution(t, r, "dipfs.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
 	testResolution(t, r, "dns1.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
 	testResolution(t, r, "dns1.example.com", 1, "/ipns/ipfs.example.com", ErrResolveRecursion)
 	testResolution(t, r, "dns2.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
@@ -122,6 +138,10 @@ func TestDNSResolution(t *testing.T) {
 	testResolution(t, r, "loop1.example.com", 2, "/ipns/loop1.example.com", ErrResolveRecursion)
 	testResolution(t, r, "loop1.example.com", 3, "/ipns/loop2.example.com", ErrResolveRecursion)
 	testResolution(t, r, "loop1.example.com", DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion)
+	testResolution(t, r, "dloop1.example.com", 1, "/ipns/loop2.example.com", ErrResolveRecursion)
+	testResolution(t, r, "dloop1.example.com", 2, "/ipns/loop1.example.com", ErrResolveRecursion)
+	testResolution(t, r, "dloop1.example.com", 3, "/ipns/loop2.example.com", ErrResolveRecursion)
+	testResolution(t, r, "dloop1.example.com", DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion)
 	testResolution(t, r, "bad.example.com", DefaultDepthLimit, "", ErrResolveFailed)
 	testResolution(t, r, "withsegment.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment", nil)
 	testResolution(t, r, "withrecsegment.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub", nil)
@@ -129,4 +149,6 @@ func TestDNSResolution(t *testing.T) {
 	testResolution(t, r, "withrecsegment.example.com/test2", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test2", nil)
 	testResolution(t, r, "withrecsegment.example.com/test3/", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test3/", nil)
 	testResolution(t, r, "withtrailingrec.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/", nil)
+	// _dnslink and . pointing to the same path is good, if they were pointing to different ones behavior would be undefined.
+	testResolution(t, r, "double.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil)
 }