diff --git a/tools/Android.mk b/tools/Android.mk
index 38415883229f36a86b3b3dd8e1732b6a196452cf..727a4d3c9b0a38d14b0cc7689de1e2c2ccf5d67d 100644
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -5,7 +5,7 @@ include $(CLEAR_VARS)
 LOCAL_MODULE := checkseapp
 LOCAL_MODULE_TAGS := optional
 LOCAL_C_INCLUDES := external/libsepol/include/
-LOCAL_CFLAGS := -DLINK_SEPOL_STATIC
+LOCAL_CFLAGS := -DLINK_SEPOL_STATIC -Wall -Werror
 LOCAL_SRC_FILES := check_seapp.c
 LOCAL_STATIC_LIBRARIES := libsepol
 
@@ -18,6 +18,7 @@ LOCAL_MODULE := checkfc
 LOCAL_MODULE_TAGS := optional
 LOCAL_C_INCLUDES := external/libsepol/include \
                     external/libselinux/include
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SRC_FILES := checkfc.c
 LOCAL_STATIC_LIBRARIES := libsepol libselinux
 
@@ -38,9 +39,21 @@ include $(CLEAR_VARS)
 
 LOCAL_MODULE := sepolicy-check
 LOCAL_MODULE_TAGS := optional
-LOCAL_C_INCLUDES := external/libsepol/include \
-                    external/libselinux/include
+LOCAL_C_INCLUDES := external/libsepol/include
+LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SRC_FILES := sepolicy-check.c
-LOCAL_STATIC_LIBRARIES := libsepol libselinux
+LOCAL_STATIC_LIBRARIES := libsepol
+
+include $(BUILD_HOST_EXECUTABLE)
+
+###################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := sepolicy-analyze
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := external/libsepol/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := sepolicy-analyze.c
+LOCAL_STATIC_LIBRARIES := libsepol
 
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/check_seapp.c b/tools/check_seapp.c
index 3ecd7b9ed7ce588ac269ac21a09ceb2d2bbc664e..ed781bfcaf745aab61a7dc214874b004f368ee82 100644
--- a/tools/check_seapp.c
+++ b/tools/check_seapp.c
@@ -476,7 +476,7 @@ static bool rule_map_validate(const rule_map *rm) {
 	bool found_name = false;
 	bool found_seinfo = false;
 	char *name = NULL;
-	key_map *tmp;
+	const key_map *tmp;
 
 	for(i=0; i < rm->length; i++) {
 		tmp = &(rm->m[i]);
diff --git a/tools/sepolicy-analyze.c b/tools/sepolicy-analyze.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b3d444c940effb51bb7e05424fa5570ceef6bb0
--- /dev/null
+++ b/tools/sepolicy-analyze.c
@@ -0,0 +1,379 @@
+#include <getopt.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/services.h>
+#include <sepol/policydb/expand.h>
+#include <sepol/policydb/util.h>
+
+void usage(char *arg0)
+{
+    fprintf(stderr, "%s [-e|--equiv] [-d|--diff] -P <policy file>\n", arg0);
+    exit(1);
+}
+
+int load_policy(char *filename, policydb_t * policydb, struct policy_file *pf)
+{
+    int fd;
+    struct stat sb;
+    void *map;
+    int ret;
+
+    fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "Can't open '%s':  %s\n", filename, strerror(errno));
+        return 1;
+    }
+    if (fstat(fd, &sb) < 0) {
+        fprintf(stderr, "Can't stat '%s':  %s\n", filename, strerror(errno));
+        close(fd);
+        return 1;
+    }
+    map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED) {
+        fprintf(stderr, "Can't mmap '%s':  %s\n", filename, strerror(errno));
+        close(fd);
+        return 1;
+    }
+
+    policy_file_init(pf);
+    pf->type = PF_USE_MEMORY;
+    pf->data = map;
+    pf->len = sb.st_size;
+    if (policydb_init(policydb)) {
+        fprintf(stderr, "Could not initialize policydb!\n");
+        close(fd);
+        munmap(map, sb.st_size);
+        return 1;
+    }
+    ret = policydb_read(policydb, pf, 0);
+    if (ret) {
+        fprintf(stderr, "error(s) encountered while parsing configuration\n");
+        close(fd);
+        munmap(map, sb.st_size);
+        return 1;
+    }
+
+    return 0;
+}
+
+static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
+                            struct avtab_node *type_rules)
+{
+    struct avtab_node *p, *c, *n;
+
+    for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
+        /*
+         * Find the insertion point, keeping the list
+         * ordered by source type, then target type, then
+         * target class.
+         */
+        if (k->source_type < c->key.source_type)
+            break;
+        if (k->source_type == c->key.source_type &&
+            k->target_type < c->key.target_type)
+            break;
+        if (k->source_type == c->key.source_type &&
+            k->target_type == c->key.target_type &&
+            k->target_class <= c->key.target_class)
+            break;
+    }
+
+    if (c &&
+        k->source_type == c->key.source_type &&
+        k->target_type == c->key.target_type &&
+        k->target_class == c->key.target_class) {
+        c->datum.data |= d->data;
+        return 0;
+    }
+
+    /* Insert the rule */
+    n = malloc(sizeof(struct avtab_node));
+    if (!n) {
+        fprintf(stderr, "out of memory\n");
+        exit(1);
+    }
+
+    n->key = *k;
+    n->datum = *d;
+    n->next = p->next;
+    p->next = n;
+    return 0;
+}
+
+static int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d,
+                                    void *args)
+{
+    struct avtab_node *type_rules = args;
+    avtab_key_t key;
+
+    /*
+     * Insert the rule into the list for
+     * the source type.  The source type value
+     * is cleared as we want to compare against other type
+     * rules with different source types.
+     */
+    key = *k;
+    key.source_type = 0;
+    if (k->source_type == k->target_type) {
+        /* Clear target type as well; this is a self rule. */
+        key.target_type = 0;
+    }
+    if (insert_type_rule(&key, d, &type_rules[k->source_type - 1]))
+        return -1;
+
+    if (k->source_type == k->target_type)
+        return 0;
+
+    /*
+     * If the target type differs, then we also
+     * insert the rule into the list for the target
+     * type.  We clear the target type value so that
+     * we can compare against other type rules with
+     * different target types.
+     */
+    key = *k;
+    key.target_type = 0;
+    if (insert_type_rule(&key, d, &type_rules[k->target_type - 1]))
+        return -1;
+
+    return 0;
+}
+
+static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
+{
+    if (k->specified & AVTAB_ALLOWED)
+        return create_type_rules_helper(k, d, args);
+    return 0;
+}
+
+static int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d,
+                                  void *args)
+{
+    if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) ==
+        (AVTAB_ALLOWED|AVTAB_ENABLED))
+        return create_type_rules_helper(k, d, args);
+    return 0;
+}
+
+static void free_type_rules(struct avtab_node *l)
+{
+    struct avtab_node *tmp;
+
+    while (l) {
+        tmp = l;
+        l = l->next;
+        free(tmp);
+    }
+}
+
+static void display_allow(policydb_t *policydb, struct avtab_node *n, int idx,
+                         uint32_t perms)
+{
+    printf("    allow %s %s:%s { %s };\n",
+           policydb->p_type_val_to_name[n->key.source_type
+                                        ? n->key.source_type - 1 : idx],
+           n->key.target_type == n->key.source_type ? "self" :
+           policydb->p_type_val_to_name[n->key.target_type
+                                        ? n->key.target_type - 1 : idx],
+           policydb->p_class_val_to_name[n->key.target_class - 1],
+           sepol_av_to_string
+           (policydb, n->key.target_class, perms));
+}
+
+static int find_match(policydb_t *policydb, struct avtab_node *l1,
+                      int idx1, struct avtab_node *l2, int idx2)
+{
+    struct avtab_node *c;
+    uint32_t perms1, perms2;
+
+    for (c = l2; c; c = c->next) {
+        if (l1->key.source_type < c->key.source_type)
+            break;
+        if (l1->key.source_type == c->key.source_type &&
+            l1->key.target_type < c->key.target_type)
+            break;
+        if (l1->key.source_type == c->key.source_type &&
+            l1->key.target_type == c->key.target_type &&
+            l1->key.target_class <= c->key.target_class)
+            break;
+    }
+
+    if (c &&
+        l1->key.source_type == c->key.source_type &&
+        l1->key.target_type == c->key.target_type &&
+        l1->key.target_class == c->key.target_class) {
+        perms1 = l1->datum.data & ~c->datum.data;
+        perms2 = c->datum.data & ~l1->datum.data;
+        if (perms1 || perms2) {
+            if (perms1)
+                display_allow(policydb, l1, idx1, perms1);
+            if (perms2)
+                display_allow(policydb, c, idx2, perms2);
+            printf("\n");
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int analyze_types(policydb_t * policydb, char equiv, char diff)
+{
+    avtab_t exp_avtab, exp_cond_avtab;
+    struct avtab_node *type_rules, *l1, *l2;
+    struct type_datum *type;
+    size_t i, j;
+
+    /*
+     * Create a list of access vector rules for each type
+     * from the access vector table.
+     */
+    type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim);
+    if (!type_rules) {
+        fprintf(stderr, "out of memory\n");
+        exit(1);
+    }
+    memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim);
+
+    if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) {
+        fputs("out of memory\n", stderr);
+        return -1;
+    }
+
+    if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) {
+        fputs("out of memory\n", stderr);
+        avtab_destroy(&exp_avtab);
+        return -1;
+    }
+
+    if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) {
+        fputs("out of memory\n", stderr);
+        avtab_destroy(&exp_avtab);
+        return -1;
+    }
+
+    if (avtab_map(&exp_avtab, create_type_rules, type_rules))
+        exit(1);
+
+    if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules))
+        exit(1);
+
+    avtab_destroy(&exp_avtab);
+    avtab_destroy(&exp_cond_avtab);
+
+    /*
+     * Compare the type lists and identify similar types.
+     */
+    for (i = 0; i < policydb->p_types.nprim - 1; i++) {
+        if (!type_rules[i].next)
+            continue;
+        type = policydb->type_val_to_struct[i];
+        if (type->flavor) {
+            free_type_rules(type_rules[i].next);
+            type_rules[i].next = NULL;
+            continue;
+        }
+        for (j = i + 1; j < policydb->p_types.nprim; j++) {
+            type = policydb->type_val_to_struct[j];
+            if (type->flavor) {
+                free_type_rules(type_rules[j].next);
+                type_rules[j].next = NULL;
+                continue;
+            }
+            for (l1 = type_rules[i].next, l2 = type_rules[j].next;
+                 l1 && l2; l1 = l1->next, l2 = l2->next) {
+                if (l1->key.source_type != l2->key.source_type)
+                    break;
+                if (l1->key.target_type != l2->key.target_type)
+                    break;
+                if (l1->key.target_class != l2->key.target_class
+                    || l1->datum.data != l2->datum.data)
+                    break;
+            }
+            if (l1 || l2) {
+                if (diff) {
+                    printf
+                        ("Types %s and %s differ, starting with:\n",
+                         policydb->p_type_val_to_name[i],
+                         policydb->p_type_val_to_name[j]);
+
+                    if (l1 && l2) {
+                        if (find_match(policydb, l1, i, l2, j))
+                            continue;
+                        if (find_match(policydb, l2, j, l1, i))
+                            continue;
+                    }
+                    if (l1)
+                        display_allow(policydb, l1, i, l1->datum.data);
+                    if (l2)
+                        display_allow(policydb, l2, j, l2->datum.data);
+                    printf("\n");
+                }
+                continue;
+            }
+            free_type_rules(type_rules[j].next);
+            type_rules[j].next = NULL;
+            if (equiv) {
+                printf("Types %s and %s are equivalent.\n",
+                       policydb->p_type_val_to_name[i],
+                       policydb->p_type_val_to_name[j]);
+            }
+        }
+        free_type_rules(type_rules[i].next);
+        type_rules[i].next = NULL;
+    }
+
+    free(type_rules);
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    char *policy = NULL;
+    struct policy_file pf;
+    policydb_t policydb;
+    char ch;
+    char equiv = 0, diff = 0;
+
+    struct option long_options[] = {
+        {"equiv", no_argument, NULL, 'e'},
+        {"diff", no_argument, NULL, 'd'},
+        {"policy", required_argument, NULL, 'P'},
+        {NULL, 0, NULL, 0}
+    };
+
+    while ((ch = getopt_long(argc, argv, "edP:", long_options, NULL)) != -1) {
+        switch (ch) {
+        case 'e':
+            equiv = 1;
+            break;
+        case 'd':
+            diff = 1;
+            break;
+        case 'P':
+            policy = optarg;
+            break;
+        default:
+            usage(argv[0]);
+        }
+    }
+
+    if (!policy || (!equiv && !diff))
+        usage(argv[0]);
+
+    if (load_policy(policy, &policydb, &pf))
+        exit(1);
+
+    analyze_types(&policydb, equiv, diff);
+
+    policydb_destroy(&policydb);
+
+    return 0;
+}
diff --git a/tools/sepolicy-check.c b/tools/sepolicy-check.c
index ad75d16d82d03efdfcc0a62f31bd76e86a6bb487..713e7c16a0afcf31a71d1bcdbad262227db7fe89 100644
--- a/tools/sepolicy-check.c
+++ b/tools/sepolicy-check.c
@@ -1,11 +1,3 @@
-/*
- * This was derived from public domain works with updates to
- * work with more modern SELinux libraries.
- *
- * It is released into the public domain.
- *
- */
-
 #include <getopt.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -133,6 +125,8 @@ int check_rule(char *s, char *t, char *c, char *p, policydb_t *policy) {
 	avtab_key_t key;
 	int match;
 
+	key.source_type = key.target_type = key.target_class = 0;
+
 	if (s_op != ANY) {
 		src = hashtab_search(policy->p_types.table, s);
 		if (src == NULL) {