diff --git a/cmd/policy/main.go b/cmd/policy/main.go
index 05675f9928cbcb56dbf042b5056e7ad6ea8daa4d..d84be447017b61b5d62381c335093d058767f998 100644
--- a/cmd/policy/main.go
+++ b/cmd/policy/main.go
@@ -25,6 +25,7 @@ import (
 	"code.vereign.com/gaiax/tsa/policy/internal/service"
 	"code.vereign.com/gaiax/tsa/policy/internal/service/health"
 	"code.vereign.com/gaiax/tsa/policy/internal/service/policy"
+	"code.vereign.com/gaiax/tsa/policy/internal/storage"
 )
 
 var Version = "0.0.0+development"
@@ -41,7 +42,9 @@ func main() {
 	}
 	defer logger.Sync() //nolint:errcheck
 
-	logger.Info("staring policy service", zap.String("version", Version), zap.String("goa", goa.Version()))
+	logger.Info("policy service started", zap.String("version", Version), zap.String("goa", goa.Version()))
+
+	storage := storage.New()
 
 	// create services
 	var (
@@ -49,7 +52,7 @@ func main() {
 		healthSvc goahealth.Service
 	)
 	{
-		policySvc = policy.New()
+		policySvc = policy.New(storage, logger)
 		healthSvc = health.New()
 	}
 
diff --git a/internal/service/policy/service.go b/internal/service/policy/service.go
index ed8edcb5878852a986a628cc9c50f237e733de10..6ccad263e5d282dbc84160f25a2775b63f910775 100644
--- a/internal/service/policy/service.go
+++ b/internal/service/policy/service.go
@@ -3,16 +3,69 @@ package policy
 import (
 	"context"
 
+	"github.com/open-policy-agent/opa/rego"
+	"go.uber.org/zap"
+
 	"code.vereign.com/gaiax/tsa/golib/errors"
 	"code.vereign.com/gaiax/tsa/policy/gen/policy"
+	"code.vereign.com/gaiax/tsa/policy/internal/storage"
 )
 
-type Service struct{}
+type Storage interface {
+	Policy(ctx context.Context, name, group, version string) (*storage.Policy, error)
+}
 
-func New() *Service {
-	return &Service{}
+type Service struct {
+	storage Storage
+	logger  *zap.Logger
 }
 
-func (s *Service) Evaluate(context.Context, *policy.EvaluateRequest) (*policy.EvaluateResult, error) {
-	return nil, errors.New("not implemented")
+func New(storage Storage, logger *zap.Logger) *Service {
+	return &Service{
+		storage: storage,
+		logger:  logger,
+	}
+}
+
+func (s *Service) Evaluate(ctx context.Context, req *policy.EvaluateRequest) (*policy.EvaluateResult, error) {
+	pol, err := s.storage.Policy(ctx, req.PolicyName, req.Group, req.Version)
+	if err != nil {
+		s.logger.Error("error getting policy from storage", zap.Error(err))
+		if errors.Is(errors.NotFound, err) {
+			return nil, err
+		}
+		return nil, errors.New("error evaluating policy", err)
+	}
+
+	if pol.Locked {
+		return nil, errors.New(errors.Forbidden, "policy is locked")
+	}
+
+	query, err := rego.New(
+		rego.Module(pol.Filename, pol.Rego),
+		rego.Query("result = data.gaiax.result"),
+	).PrepareForEval(ctx)
+	if err != nil {
+		s.logger.Error("error preparing rego query", zap.Error(err))
+		return nil, errors.New("error preparing rego query", err)
+	}
+
+	resultSet, err := query.Eval(ctx, rego.EvalInput(req.Data))
+	if err != nil {
+		s.logger.Error("error evaluating rego query", zap.Error(err))
+		return nil, errors.New("error evaluating rego query", err)
+	}
+
+	if len(resultSet) == 0 {
+		s.logger.Error("policy evaluation result set is empty")
+		return nil, errors.New("policy evaluation result set is empty")
+	}
+
+	result, ok := resultSet[0].Bindings["result"]
+	if !ok {
+		s.logger.Error("policy result bindings not found")
+		return nil, errors.New("policy result bindings not found")
+	}
+
+	return &policy.EvaluateResult{Result: result}, nil
 }
diff --git a/internal/storage/policies_tmp_store.go b/internal/storage/policies_tmp_store.go
new file mode 100644
index 0000000000000000000000000000000000000000..0bbba0d6782768cf134ae029ab18cf6fc2ee1a9f
--- /dev/null
+++ b/internal/storage/policies_tmp_store.go
@@ -0,0 +1,25 @@
+package storage
+
+import "time"
+
+// Temporary hardcoded policy storage as a simple map.
+// When we finalize with Steffen how we're going to store
+// and synchronize policy files, this will be replaced with
+// real policy store.
+var policies = map[string]*Policy{
+	"example:example:1.0": {
+		Filename:    "example_1.0.rego",
+		Name:        "example",
+		Group:       "example",
+		Version:     "1.0",
+		Locked:      false,
+		LastUpdated: time.Now(),
+		Rego: `
+			package gaiax
+		
+			default result = {}
+
+			result = {"taskID":123}
+		`,
+	},
+}
diff --git a/internal/storage/storage.go b/internal/storage/storage.go
new file mode 100644
index 0000000000000000000000000000000000000000..0a43d6ae09bd80ed824f25362a7fcddde15ea05b
--- /dev/null
+++ b/internal/storage/storage.go
@@ -0,0 +1,36 @@
+package storage
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"code.vereign.com/gaiax/tsa/golib/errors"
+)
+
+type Policy struct {
+	Filename    string
+	Name        string
+	Group       string
+	Version     string
+	Rego        string
+	Locked      bool
+	LastUpdated time.Time
+}
+
+type Storage struct{}
+
+func New() *Storage {
+	return &Storage{}
+}
+
+func (s *Storage) Policy(ctx context.Context, name, group, version string) (*Policy, error) {
+	key := fmt.Sprintf("%s:%s:%s", name, group, version)
+
+	policy, ok := policies[key]
+	if !ok {
+		return nil, errors.New(errors.NotFound, "policy not found in storage")
+	}
+
+	return policy, nil
+}